package com.zhdl.modules.prefiresys.web.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhdl.common.util.WebResult;
import com.zhdl.modules.prefiresys.entity.DetectorHistoryData;
import com.zhdl.modules.prefiresys.entity.FactoryLocalHost;
import com.zhdl.modules.prefiresys.service.*;
import com.zhdl.modules.prefiresys.web.request.*;
import com.zhdl.modules.prefiresys.web.response.*;
import com.zhdl.modules.prefiresys.web.service.CollectService;
import org.java_websocket.client.WebSocketClient;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 业务接口
 */
@RestController
@RequestMapping("/api/v1")
public class ApiController {

    private static final long DEFAULT_TIMEOUT = 30 * 60 * 1000;
    private static final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    private final Map<Integer, SseEmitter> sseEmitters = new ConcurrentHashMap<>();
    private final CollectService collectService;
    private final FactoryLocalHostService factoryLocalHostService;
    private final DefAreaAlarmRecService defAreaAlarmRecService;
    private final EventRecordsService eventRecordsService;
    private final DetectorAnalogRecService detectorAnalogRecService;
    private final DetectorSwitchRecService detectorSwitchRecService;
    private final DetectorHistoryDataService detectorHistoryDataService;
    private final DetectorBlowBackLogService detectorBlowBackLogService;
    private final DefAreaHourRecService defAreaHourRecService;
    private final FactoryWeeklyRiskService factoryWeeklyRiskService;
    private long sseSeq;


    /**
     * 初始化
     *
     * @param collectService1
     * @param defAreaHourRecService
     * @param defAreaAlarmRecService
     * @param detectorAnalogRecService
     * @param detectorSwitchRecService
     * @param detectorHistoryDataService
     * @param detectorBlowBackLogService
     * @param factoryWeeklyRiskService
     * @param factoryLocalHostService
     */
    public ApiController(CollectService collectService1, DefAreaHourRecService defAreaHourRecService, DefAreaAlarmRecService defAreaAlarmRecService,
                         DetectorAnalogRecService detectorAnalogRecService,
                         DetectorSwitchRecService detectorSwitchRecService,
                         DetectorHistoryDataService detectorHistoryDataService,
                         DetectorBlowBackLogService detectorBlowBackLogService, FactoryWeeklyRiskService factoryWeeklyRiskService,
                         FactoryLocalHostService factoryLocalHostService, EventRecordsService eventRecordsService) {
        this.collectService = collectService1;
        this.defAreaHourRecService = defAreaHourRecService;
        this.defAreaAlarmRecService = defAreaAlarmRecService;
        this.detectorAnalogRecService = detectorAnalogRecService;
        this.detectorSwitchRecService = detectorSwitchRecService;
        this.detectorHistoryDataService = detectorHistoryDataService;
        this.detectorBlowBackLogService = detectorBlowBackLogService;
        this.factoryWeeklyRiskService = factoryWeeklyRiskService;
        this.factoryLocalHostService = factoryLocalHostService;
        this.eventRecordsService = eventRecordsService;
    }

    /**
     * 查询所有事件
     */

    /**
     * 多条件分页查询事件记录
     * querydsl 查询
     *
     * @param request 事件记录
     * @return
     */
    @PostMapping("/get/event/rec/page/data/{pageSize}/{pageNumber}")
    public WebResult<Page<EventRecordsResp>> getEventRecPageData(@RequestBody @Validated EventRecordsListRequest request, @PathVariable int pageNumber, @PathVariable int pageSize) {
        //分页
        Pageable pageable = PageRequest.of(pageNumber, pageSize);
        Page<EventRecordsResp> allPage = eventRecordsService.findAllRecord(request, pageable);
        return WebResult.okResult(allPage);
    }

    /**
     * 根据事件Id查询
     */
    @PostMapping("/get/event/info/page/data")
    public WebResult<List<EventAlarmInfoResp>> getEventRecPageData(@RequestBody EventAlarmInfoReq request) {
        List<EventAlarmInfoResp> alarmByEventId = eventRecordsService.findAlarmByEventId(request);
        return WebResult.okResult(alarmByEventId);
    }

    /**
     * 获取SSE序号
     */
    private long getSseSeq() {
        if (sseSeq > 65535L * 65535)
            sseSeq = 0;
        return sseSeq++;
    }

    private WebSocketClient webSocketClientExample;

    /**
     * 首页数据请求
     */
    @GetMapping(value = "/sse/home/{id}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter handleSse(@PathVariable Integer id) {
        SseEmitter emitter = new SseEmitter();
        sseEmitters.put(id, emitter);
        // 超时移除
        emitter.onTimeout(() -> {
            emitter.complete();
            sseEmitters.remove(id);
        });
        // 完成移除
        emitter.onCompletion(() -> sseEmitters.remove(id));
        // 每一秒发送一条消息
        executorService.scheduleAtFixedRate(() -> {
            ObjectMapper mapper = new ObjectMapper();
            //if(ErrorMsgQueue.size() > 0)
            //    collectService.sseResp.setErrorMsg(ErrorMsgQueue.pop());//6-28 演示暂时注释掉
            //else
            collectService.sseResp.setErrorMsg(null);
            WebResult<HomeSseRespData> sseResp = WebResult.okResult(collectService.sseResp);
            try {
                emitter.send(SseEmitter.event().id(String.valueOf(getSseSeq())).data(mapper.writeValueAsString(sseResp), MediaType.APPLICATION_JSON));
            } catch (IOException e) {
                emitter.complete();
            }
        }, 0, 1, TimeUnit.SECONDS);

        return emitter;
    }

    /**
     * 首页数据请求，仅返回一次数据，方便查看参数说明
     *
     * @return
     */
    @GetMapping("/get/home/data")
    public WebResult<HomeSseRespData> getHomeData() {
        return WebResult.okResult(collectService.sseResp);
    }


    /**
     * 近7日风险趋势，包含月风险等级数据
     *
     * @return
     */
    @PostMapping("/ago/7day/risk/trend")
    public WebResult<AgoWeekRiskTrendHomeData> agoWeekRiskTrend() {

        // 近7日风险趋势，月风险等级数据
        AgoWeekRiskTrendHomeData data = new AgoWeekRiskTrendHomeData();

        // 七日风险数据表
        DayAlarmCountData[] dayItems = new DayAlarmCountData[7];

        //查出 七日报警的所有数据
        List<Object[]> agoWeekAlarmCount = defAreaAlarmRecService.statAgoWeekAlarmCount_1();

        //周报警数
        Long weekAlarmCount = 0L;

        // (0) 规定返回的日期格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        //（1）获取当前时间
        LocalDateTime dateNow = LocalDateTime.now();

        for (int day = 0; day < 7; day++) {

            //（2）获取 一周每一天的日期
            LocalDateTime localDateTime = dateNow.minusDays(6 - day);

            // 传入String类型的当前格式
            dayItems[day] = new DayAlarmCountData(dateTimeFormatter.format(localDateTime), 0L);

            for (int j = 0; j < agoWeekAlarmCount.size(); j++) {
                //判断有无七日内数据，如果有 则保存
                if (dayItems[day].getDate().equals((String) agoWeekAlarmCount.get(j)[0])) {
                    // 表中格式为 Date[0] -- Count[1]
                    BigInteger dayAlarm = (BigInteger) agoWeekAlarmCount.get(j)[1];
                    // 传入 date表中
                    dayItems[day].setCount(dayAlarm.longValue());
                }

            }

            //保存一天的报警数量
            weekAlarmCount += dayItems[day].getCount();

        }
        //七日数据保存到data中
        //data.setAgoWeekAlarmCountList(dayItems);
        data.setAgo7DayAlarmCountList(dayItems);

        //查找一个月报警信息
        FactoryLocalHost factoryLocalHost = factoryLocalHostService.findRecently();
        //周报警总数保存到data中
        //data.setWeekAlarmCount(localHost.getWeekAlarmCount());
        data.setWeekAlarmCount(weekAlarmCount.intValue());

        Integer allAlarm = factoryLocalHostService.findAllAlarm();
        //报警总数保存到data中
        data.setMonthAlarmCount(allAlarm);
//        data.setTotalAlarmCount(allAlarm);

        /**
         * ------------------------------------------------------------------------
         * 从 alarm 中查询每一个月的报警等级次数
         */
        List<Object[]> monthAlarmNo1 = defAreaAlarmRecService.statMonthAlarmNo1();

        List<Object[]> monthAlarmNo2 = defAreaAlarmRecService.statMonthAlarmNo2();

        List<Object[]> monthAlarmNo3 = defAreaAlarmRecService.statMonthAlarmNo3();


        int month1 = 0;
        int month2 = 0;
        int month3 = 0;


        for (Object[] objects : monthAlarmNo1) {
            BigInteger b = (BigInteger) objects[1];
            month3 += b.intValue();
        }

        for (Object[] objects : monthAlarmNo2) {
            BigInteger b = (BigInteger) objects[1];
            month2 += b.intValue();
        }

        for (Object[] objects : monthAlarmNo3) {
            BigInteger b = (BigInteger) objects[1];
            month1 += b.intValue();
        }

        //---------------------------------------------------------------------------

        data.setMonthAlarm1(month1);
        data.setMonthAlarm2(month2);
        data.setMonthAlarm3(month3);

        //添加故障数到data
//        data.setMonthDeviceFailCount(factoryLocalHost.getMonthDeviceFailCount());
        FactoryLocalHost factoryLocalHost1 = factoryLocalHostService.getAllTotalHost().get(0);

        data.setMonthDeviceFailCount(factoryLocalHost1.getMonthDeviceFailCount());

        /**
         * 风险等级 --但是没用
         */
//        collectService.sseResp.setRiskGrade(getRiskGrade(localHost.getWeekAlarmCount(), localHost.getRiskGradeLine()));
        collectService.sseResp.setRiskGrade(1);


        return WebResult.okResult(data);
    }

    @GetMapping(path = "/get/area/percent/day/allLists/{id}")
    public WebResult<List<AreaPercentRespData>> getAreaPercentAllLists(@PathVariable String id) {

        // 从数据库查询
        List<DetectorHistoryData> list = detectorHistoryDataService.findNullAndData(id);
        // 组装返回的数据
        List<AreaPercentRespData> outList = new ArrayList<>();
        // 将数据存放到 data 中
        for (DetectorHistoryData entity : list) {
            AreaPercentRespData item = new AreaPercentRespData();

            item.setTime(entity.getCreateDate());
            item.setParticlePercent(entity.getParticlePercent());
            item.setSmokePercent(entity.getSmokePercent());

            outList.add(item);
        }

        return WebResult.okResult(outList);
    }

    /**
     * 查询某防区两小时内浓度数据
     *
     * @param id 防区id
     * @return
     */
    @GetMapping(path = "/get/area/percent/day/lists/{id}")
    public WebResult<List<AreaPercentRespData>> getAreaPercentLists(@PathVariable String id) {

        // 从数据库查询
        List<DetectorHistoryData> list = detectorHistoryDataService.findByAreaId(id);
        // 组装返回的数据
        List<AreaPercentRespData> outList = new ArrayList<>();
        // 将数据存放到 data 中
        for (DetectorHistoryData entity : list) {
            AreaPercentRespData item = new AreaPercentRespData();

            item.setTime(entity.getCreateDate());
            item.setParticlePercent(entity.getParticlePercent());
            item.setSmokePercent(entity.getSmokePercent());

            outList.add(item);
        }

        return WebResult.okResult(outList);
    }

    @PostMapping("/get/history/day/data")
    public WebResult<List<HistoryListResp>> getHistoryDayDate(@RequestBody @Validated DayHistoryListRequest request) {
        List<HistoryListResp> allPage = detectorHistoryDataService.findDayAllRecord(request);
        return WebResult.okResult(allPage);
    }

    /**
     * 多条件分页查询报警记录
     * querydsl 查询
     *
     * @param request 报警记录
     * @return
     */
    @PostMapping("/get/alarm/rec/page/data/{pageSize}/{pageNumber}")
    public WebResult<Page<AlarmRecListResp>> getAlarmRecPageData(@RequestBody @Validated AlarmRecListRequest request, @PathVariable int pageNumber, @PathVariable int pageSize) {

        //分页
        Pageable pageable = PageRequest.of(pageNumber, pageSize);
        Page<AlarmRecListResp> allPage = defAreaAlarmRecService.findAllRecord(request, pageable);
        return WebResult.okResult(allPage);

    }


    /**
     * 多条件分页查询常规参数监测记录
     *
     * @param pageSize   每页数据量
     * @param pageNumber 当前页码，从0开始，0表示第一页
     * @param request    历史记录
     * @return
     * @mock {"pageNumber": 10, "pageSize": "0"}
     */
    @PostMapping("/get/history/page/data/{pageSize}/{pageNumber}")
    public WebResult<Page<HistoryListResp>> getHistoryPageData(@RequestBody @Validated HistoryListRequest request, @PathVariable int pageNumber, @PathVariable int pageSize) {
        Pageable pageable = PageRequest.of(pageNumber, pageSize);
        Page<HistoryListResp> allPage = detectorHistoryDataService.findAllRecord(request, pageable);
        return WebResult.okResult(allPage);
    }

    /**
     * 查询模拟量记录
     *
     * @param request
     * @return
     */
    @PostMapping("/get/analog/rec/page/data")
    public WebResult<List<AnalogRecListResp>> getAnalogRecPageData(@RequestBody @Validated AnalogRecListRequest request) {
        List<AnalogRecListResp> list = detectorAnalogRecService.findAllRecord(request);
        return WebResult.okResult(list);
    }

    /**
     * 查询开关量记录
     *
     * @param request
     * @return
     */
    @PostMapping("/get/switch/rec/page/data")
    public WebResult<List<SwitchRecListResponse>> getSwitchRecPageData(@RequestBody @Validated SwitchRecListRequest request) {
        List<SwitchRecListResponse> allPage = detectorSwitchRecService.findAllRecord(request);
        return WebResult.okResult(allPage);
    }

    /**
     * 多条件分页查询反吹记录
     *
     * @param request
     * @return
     */
    @PostMapping("/get/blow/back/page/data/{pageSize}/{pageNumber}")
    public WebResult<Page<DetectorBlowBackLogPageResp>> getBlowBackPageData(@RequestBody @Validated DetectorBlowBackLogPageRequest request, @PathVariable int pageNumber, @PathVariable int pageSize) {
        Pageable pageable = PageRequest.of(pageNumber, pageSize);
        Page<DetectorBlowBackLogPageResp> allPage = detectorBlowBackLogService.findAllRecord(request, pageable);
        return WebResult.okResult(allPage);
    }
}
